#ifndef CELL_H_
#define CELL_H_

#include <sstream>
#include <iostream>
#include <ostream>
#include <iomanip>
#include <string>
#include <iomanip>

#include "Common.h"
#include "Axis.h"

class Cell {

		Cell(const Cell&);
		Cell& operator=(const Cell& cell) {
			letter = cell.letter;
			rowZero = cell.rowZero;
			rowN = cell.rowN;
			colZero = cell.colZero;
			colN = cell.colN;
			value = cell.value;
			wordFactor = cell.wordFactor;
			letterFactor = cell.letterFactor;
			validVertChars = cell.validVertChars;
			validHoriChars = cell.validHoriChars;
			return *this;
		}

		friend class Scrabble;
		friend class Board;
		friend class ActiveLine;
		friend class Main;
		friend class Expander;

		static const uchar letterValues[26];

		uchar letter;
		bool rowZero, rowN, colZero, colN;
		ubyte value;
		ubyte wordFactor;
		ubyte letterFactor;
		u_int32_t validVertChars;
		u_int32_t validHoriChars;

		const inline u_int32_t getValidChars(Axis::Axis axis) const {
			return axis == Axis::HORIZONTAL ? validHoriChars : validVertChars;
		}

		inline void setValidChars(u_int32_t validChars, Axis::Axis axis) {
			if (axis == Axis::HORIZONTAL)
				validHoriChars = validChars;
			else
				validVertChars = validChars;
		}

		bool operator==(const Cell& other) const {
			return letter == other.letter;
			//&& value==other.value
			//&& wordFactor==other.wordFactor
			//&& letterFactor==other.letterFactor;
		}
		bool operator!=(const Cell& other) const {
			return !operator==(other);
		}

		bool validFor(const uchar ch, const Axis::Axis axis) const {
			return getValidChars(axis) & 0x1 << (ch - 'A');
		}

		inline Cell* set(uchar letter) {
			this->letter = letter;
			if (letter == Common::EMPTYCHAR)
				this->value = 0;
			else
				this->value = letterValues[letter - 'A'];
			return this;
		}

	public:

		Cell() :
			letter(0),
			rowZero(0),
			rowN(0),
			colZero(0),
			colN(0),
			value(0),
			wordFactor(0),
			letterFactor(1),
			validVertChars(0),
			validHoriChars(0)
			{
		}

		virtual ~Cell() {
		}

		void assertFilled() {
			wordFactor = 1;
			letterFactor = 1;
		}

		Cell* setWildcard(uchar letter) {
			this->letter = letter;
			this->value = 0;
			return this;
		}

		inline uchar getLetter() const {
			return letter;
		}

		inline void clear() { letter = Common::EMPTYCHAR; }

		inline bool isEmpty() const {
			return letter == Common::EMPTYCHAR;
		}

		inline bool isFilled() const {
			return letter != Common::EMPTYCHAR;
		}

		inline bool isValid() const {
			return isFilled() && ((letter >= 'A' && letter <= 'Z') || letter == '_');
		}

		inline bool isEndpoint(int direction) const {
			if(direction==-1)return colZero;
			if(direction==-Common::boardSize)return rowZero;
			if(direction==1)return colN;
			if(direction==Common::boardSize)return rowN;
			return false;
		}

		inline Cell* nextCell(int direction) {
			return this+direction;
		}

		static const ubyte UBYTE_1 = 1;
		static const ubyte UBYTE_2 = 2;
		static const ubyte UBYTE_3 = 3;

		const char *showType() const {
			if (wordFactor == UBYTE_1 && letterFactor == UBYTE_1)
				return " ";
			if (wordFactor == UBYTE_1 && letterFactor == UBYTE_3)
				return "d";
			if (wordFactor == UBYTE_1 && letterFactor == UBYTE_3)
				return "t";
			if (wordFactor == UBYTE_3)
				return ("T");
			if (wordFactor == UBYTE_2)
				return ("D");
			return "??";
		}

		std::string toString() const {
			std::ostringstream str;
			if (letter == Common::EMPTYCHAR)
				str << "          ";
			else {
				str << letter << ':' << showType() << " " << std::setw(2) << value << ':' << wordFactor << ':'
						<< letterFactor;
			}
			return str.str();
		}
};

#endif /*CELL_H_*/
